﻿using System;
using System.Collections.Generic;
using SdmxMl.Common;
using SdmxMl.Structure;
using System.Windows.Forms;
using SdmxMl.Manager;

namespace SdmxMl.Helper
{
    /// <summary>
    /// Helper class for converting a Codelist with simple hierarchy
    /// to an Artefact of type HierarchicalCodeList
    /// </summary>
    public class CodelistToHCL
    {
        #region Internal Members

        private SmManager sm;
        private TreeView tv;
        private List<CodeListType> listCL;
        CodeListType sourceCL;
        HierarchicalCodelistType sourceHe;

        #endregion

        #region public Methods for transformation

        public SmManager Transform(CodeListType clt, HierarchicalCodelistType he)
        {
            if (clt == null)
                throw new ArgumentException("Unexpected! Undefined codelist given in HierarchicalCodelist transformation.");
            sourceCL = clt;
            sourceHe = he;

            // Start naming with convensions
            sourceCL.AgencyId = he.AgencyId;
            sourceCL.Id = he.Id;
            sourceCL.Version = he.Version;
            if (sourceCL.Id.StartsWith("HCL_"))
                sourceCL.Id = he.Id.Substring(4);
            if (sourceCL.Id.StartsWith("CL_") == false)
                sourceCL.Id = "CL_" + sourceCL.Id;

            sm = new SmManager();

            // Convert codelist hierarchy to treeNodes
            tv = new TreeView();
            tv.Nodes.Add(new TreeNode("Root"));
            clt.CodeList.HasHierarchy = true;
            clt.CodeList.FillTree(tv.Nodes[0]);

            //Create a codelist for each level
            listCL = new List<CodeListType>();
            FillCodeList(tv.Nodes[0]);

            foreach (CodeListType cltLevel in listCL)
                sm.PutArtefact(SdmxArtefactType.CodeLists, cltLevel);

            if (he.Id.StartsWith("HCL_") == false)
                he.Id = "HCL_" + he.Id;

            // Create Hierarchy container
            HierarchyType heType = new HierarchyType(he.CodelistRefList);
            heType.Id = "HR_" + he.Id.Substring(4);
            heType.Name.UpdateDefaultText("Hierarchy");
            he.HierarchyList.Clear();
            he.HierarchyList.Add(heType);

            // Create references
            int aliasCd = 0;
            foreach (CodeListType cltLevel in listCL)
            {
                ++aliasCd;
                // Create references
                CodelistRefType che = new CodelistRefType();
                che.AgencyId = cltLevel.AgencyId;
                che.Id = cltLevel.Id;
                che.Alias = aliasCd.ToString();
                che.Version = cltLevel.Version;
                he.CodelistRefList.Add(che);

                LevelType level = new LevelType();
                level.Id = "LV_" + che.Alias;
                foreach (string lg in LangSupport.SupportedLanguages)
                    level.Name.UpdateForLanguage(lg, sourceHe.Name.GetForLanguage(lg) + " level " + aliasCd.ToString());

               // level.CodingType.TextType = TextTypeType.Integer;
                level.Order = aliasCd;
                heType.LevelList.Add(level);
            }

            //create hierarchy
            FillHierarchy(tv.Nodes[0], heType.CodeRefList);
            sm.PutArtefact(SdmxArtefactType.HierarchicalCodelists, he);

            return sm;
        }
        #endregion

        #region internal Methods

        private void FillCodeList(TreeNode node)
        {
            CodeListType clt = null;
            foreach (TreeNode nd in node.Nodes)
            {
                if (nd.Level > listCL.Count)
                {
                    clt = new CodeListType();
                    clt.Id = sourceCL.Id + "_L" + nd.Level.ToString();
                    foreach (string lg in LangSupport.SupportedLanguages)
                        clt.Name.UpdateForLanguage(lg, sourceHe.Name.GetForLanguage(lg) + " level " + nd.Level.ToString());
                    clt.AgencyId = sourceCL.AgencyId;
                    clt.Version = sourceCL.Version;
                    listCL.Add(clt);
                }
                else
                    clt = listCL[nd.Level - 1];

                CodeType c = nd.Tag as CodeType;
                c.Parent = string.Empty;
                clt.CodeList.Add(c);

                //Recurse
                FillCodeList(nd);
            }
        }

        private void FillHierarchy(TreeNode node, CodeRefTypeList crtl)
        {
            foreach (TreeNode nd in node.Nodes)
            {
                CodeType c = nd.Tag as CodeType;
                CodeRefType heRefcode = new CodeRefType();
                heRefcode.CodeID = c.Id;
                Annotation a = c.AnnotationList.GetAnnotationType(SdmxMl.SmsImportCfg.ImportArtefactExcel.TYPE_VALID_FROM);
                if (a != null)
                {
                    heRefcode.ValidFrom = a.Title;
                    c.AnnotationList.Remove(a);
                }
                a = c.AnnotationList.GetAnnotationType(SdmxMl.SmsImportCfg.ImportArtefactExcel.TYPE_VALID_TO);
                if (a != null)
                {
                    heRefcode.ValidTo = a.Title;
                    c.AnnotationList.Remove(a);
                }
                heRefcode.CodelistAliasRef = nd.Level.ToString();
                crtl.Add(heRefcode);

                //Recurse
                FillHierarchy(nd, heRefcode.CodeRefList);
            }
        }
        #endregion
    }
}
